﻿using System;
using System.Collections.Generic;
using System.Windows.Input;
#if SILVERLIGHT
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
#else
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
#endif

namespace Microsoft.PlayerFramework
{
    /// <summary>
    /// Behavior to support binding a command's Enabled state to a control.
    /// The Execute method on the command is not fired from this, only the enabled state is affected.
    /// </summary>
    public static class ControlBehavior
    {
        /// <summary>
        /// Identifies the Command dependency property.
        /// </summary>
        public static readonly DependencyProperty CommandProperty = DependencyProperty.RegisterAttached("Command", typeof(ICommand), typeof(ControlBehavior), new PropertyMetadata(null, Attach));

        /// <summary>
        /// Sets the command for a given control.
        /// </summary>
        /// <param name="obj">The dependency object to attach the command to.</param>
        /// <param name="propertyValue">The command to attach.</param>
        public static void SetCommand(DependencyObject obj, ICommand propertyValue)
        {
            if (obj == null) throw new ArgumentNullException("obj");
            obj.SetValue(CommandProperty, propertyValue);
        }

        /// <summary>
        /// Gets the command associated with the control.
        /// </summary>
        /// <param name="obj">The  control to get the associated command for.</param>
        /// <returns>The command associated with the control.</returns>
        public static ICommand GetCommand(DependencyObject obj)
        {
            if (obj == null) throw new ArgumentNullException("obj");
            return obj.GetValue(CommandProperty) as ICommand;
        }

        static Dictionary<Control, Action> DetachActions = new Dictionary<Control, Action>();

        static void Attach(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var control = d as Control;
            if (control != null)
            {
                var oldValue = e.OldValue as ICommand;
                var newValue = e.NewValue as ICommand;
                if (oldValue != null) DetachCommand(control);
                if (newValue != null) AttachCommand(control, newValue);
            }
        }

        static void AttachCommand(Control control, ICommand command)
        {
            control.IsEnabled = command.CanExecute(null);
            EventHandler CanExecuteChangedEventHandler = (s, e) => control.IsEnabled = command.CanExecute(null);
            command.CanExecuteChanged += CanExecuteChangedEventHandler;

            DetachActions.Add(control, () =>
            {
                command.CanExecuteChanged -= CanExecuteChangedEventHandler;
            });
        }

        static void DetachCommand(Control control)
        {
            var action = DetachActions[control];
            action();
            DetachActions.Remove(control);
        }

    }
}
